#include <GL/glew.h>
#include <GL/glut.h>

#include <vector>
#include "BezierCuadCurve.h"
#include "BezierCubCurve.h"
#include "BSplineCuadCurve.h"
#include "BSplineCubCurve.h"

using namespace std;

void addPoint(vector<float>*,float,float,float);
vector<float>* createPoints();

void loadCurves();
void drawCurves();
void addAxis();

void keyboard(unsigned char,int,int);
void handleResize(int,int);
void drawScene();

void freeMem();

float windowWidth  = 800.0f;
float windowHeight = 600.0f;

GLfloat rotx = 0.0;
GLfloat roty = 0.0;
GLfloat rotz = 0.0;

vector<float>* puntosControl;
BezierCuadCurve* bezierCuad;
BezierCubCurve* bezierCub;
BSplineCuadCurve* bEsplineCuad;
BSplineCubCurve* bEsplineCub;

int main(int argc, char** argv) {
 //Initialize GLUT
 glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
 glutInitWindowSize(windowWidth,windowHeight);
	
 //Create the window
 glutCreateWindow("Project");
 glEnable(GL_DEPTH_TEST);
	
 //Set handler functions
 glutDisplayFunc(drawScene);		// drawing function
 glutKeyboardFunc(keyboard);		// keyboard function
 glutReshapeFunc(handleResize);		// for reshaping the window		 

 loadCurves();

 // Main Loop  
 glutMainLoop();
 return 0;
}

//Called when the window is resized
void handleResize(int w, int h) {
 glViewport(0, 0, w, h);
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
 gluPerspective(45.0, (double)w / (double)h, 1.0, 200.0);
}

//Draws the 3D scene
void drawScene() {
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glMatrixMode(GL_MODELVIEW); //Switch to the drawing perspective

 drawCurves();
 glutSwapBuffers();
}

void keyboard(unsigned char key, int x, int y)
{
 switch (key) {
   case 'x':
   case 'X':
      rotx = rotx - 10.0f;
      glutPostRedisplay();
      break;
   case 's':
   case 'S':
      rotx = rotx + 10.0f;
      glutPostRedisplay();
      break;
   case 'y':
   case 'Y':
      roty = roty + 10.0f;
      glutPostRedisplay();
      break;
   case 't':
   case 'T':
      roty = roty - 10.0f;
      glutPostRedisplay();
      break;
   case 'a':
   case 'A':
      rotz = rotz - 10.0f;
      glutPostRedisplay();
      break;
   case 'z':
   case 'Z':
      rotz = rotz + 10.0f;
      glutPostRedisplay();
      break;

   case 27:
      freeMem();
      exit(0);
      break;
   }
}

// curvas
// ------------------------------------------------------------------
void loadCurves(){
 puntosControl = createPoints();

 float vectPerp[3] = {0,0,1};

 bezierCuad = new BezierCuadCurve(puntosControl,vectPerp);
 bezierCub  = new BezierCubCurve(puntosControl,vectPerp);

 bEsplineCuad = new BSplineCuadCurve(puntosControl,vectPerp);
 bEsplineCub  = new BSplineCubCurve(puntosControl,vectPerp);
}

vector<float>* createPoints(){
 vector<float>* PuntosControl = new vector<float>();

 addPoint(PuntosControl,-1,2,2);
 addPoint(PuntosControl,1,1,2);
 addPoint(PuntosControl,2,2,2);
 addPoint(PuntosControl,3,-2,4);
 addPoint(PuntosControl,4,0,4);
 addPoint(PuntosControl,5,1,4);
 addPoint(PuntosControl,6,0,-2);
 addPoint(PuntosControl,7,1,-2);
 addPoint(PuntosControl,6,3,-2);
 addPoint(PuntosControl,9,0,0);

 return PuntosControl;
}

void addPoint(vector<float>* vector,float x,float y, float z){
	vector->push_back(x);
	vector->push_back(y);
	vector->push_back(z);
}

void drawCurves(){

 glLoadIdentity(); 
 glTranslatef(-4.0f, 0.0f, -15.0f);
 glRotatef(rotx, 1.0, 0.0, 0.0);
 glRotatef(roty, 0.0, 1.0, 0.0);
 glRotatef(rotz, 0.0, 0.0, 1.0);

 glColor3f(1.0f,1.0f,1.0f);
 addAxis();

 bezierCuad->drawControlPoints();
 glColor3f(1.0f,0.0f,0.0f); 
 bezierCuad->drawCurve(glm::mat4(1.0));

 glColor3f(1.0f,1.0f,1.0f);
 bezierCub->drawControlPoints();
 glColor3f(1.0f,1.0f,0.0f); 
 bezierCub->drawCurve(glm::mat4(1.0));

 glColor3f(1.0f,1.0f,1.0f);
 bEsplineCuad->drawControlPoints();
 glColor3f(0.0f,0.0f,1.0f); 
 bEsplineCuad->drawCurve(glm::mat4(1.0));

 glColor3f(1.0f,1.0f,1.0f);
 bEsplineCub->drawControlPoints();
 glColor3f(0.0f,1.0f,1.0f); 
 bEsplineCub->drawCurve(glm::mat4(1.0));
}

void addAxis(){
 glBegin(GL_LINE_LOOP);
 	glVertex3f(-100.0f,0.0f,-1.0f);
 	glVertex3f(100.0f,0.0f,-1.0f);
 glEnd();

 glBegin(GL_LINE_LOOP);
 	glVertex3f(0.0f,-100.0f,-1.0f);
 	glVertex3f(0.0f,100.0f,-1.0f);
 glEnd();

}

void freeMem(){
 delete(puntosControl);
 delete(bezierCuad); 
 delete(bezierCub);
 delete(bEsplineCuad);
 delete(bEsplineCub);
}
